package com.jrx.anytxn.param.service.investor.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.common.exception.TxnException;
import com.jrx.anytxn.common.exception.TxnRuntimeException;
import com.jrx.anytxn.common.uitl.BeanMapping;
import com.jrx.anytxn.common.uitl.StringUtils;
import com.jrx.anytxn.i18n.response.TxnPage;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.constant.ErrorMsgConstant;
import com.jrx.anytxn.param.dto.investor.HandleInvestorLimitReq;
import com.jrx.anytxn.param.dto.investor.HandleInvestorLimitRes;
import com.jrx.anytxn.param.dto.investor.PrInvestorTableReq;
import com.jrx.anytxn.param.dto.investor.PrInvestorTableRes;
import com.jrx.anytxn.param.entity.PrInvestorLimit;
import com.jrx.anytxn.param.entity.PrInvestorTable;
import com.jrx.anytxn.param.mapper.ext.ExtPrInvestorLimitMapper;
import com.jrx.anytxn.param.mapper.ext.ExtPrInvestorTableMapper;
import com.jrx.anytxn.param.service.investor.IPrInvestorTableService;
import com.jrx.anytxn.redisson.service.RedissonLockService;
import com.jrx.anytxn.redisson.util.LockType;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

/**
 * 出资方表 service实现类
 *
 * @author 黄秋平
 * @date 2020-05-12 9:42
 **/
@Service
@CacheConfig(cacheNames = "INVESTOR_TABLE")
public class PrInvestorTableServiceImpl implements IPrInvestorTableService {

    private static final Logger logger = LoggerFactory.getLogger(PrInvestorTableServiceImpl.class);

    @Resource
    private ExtPrInvestorTableMapper extPrInvestorTableMapper;

    @Resource
    private ExtPrInvestorLimitMapper extPrInvestorLimitMapper;

    @Resource
    private ISegmentService segmentService;

    @Autowired
    private RedissonLockService redissonLockService;

    @Override
    public TxnPage<PrInvestorTableRes> findAllPageByTenId(Integer pageNum, Integer pageSize, String tenantId) throws TxnException{
        Page<PrInvestorTable> page = PageHelper.startPage(pageNum, pageSize, Constant.ORDER_BY_SORT);
        List<PrInvestorTable> investorTableList = extPrInvestorTableMapper.selectByTenantId(tenantId,null);
        if (investorTableList.isEmpty()) {
            logger.error(TxnRespCode.NO_DATA.getMsg());
            throw new TxnException(TxnRespCode.NO_DATA.getMsg());
        }
        List<PrInvestorTableRes> res = BeanMapping.copyList(investorTableList, PrInvestorTableRes.class);
        return new TxnPage<>(pageNum, pageSize, page.getTotal(), res);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PrInvestorTableRes addInvestorTable(PrInvestorTableReq prInvestorTableReq) throws TxnException {
        if(prInvestorTableReq.getInvestorCreditLimit()!=null&&prInvestorTableReq.getInvestorLoanLimit()!=null&&prInvestorTableReq.getSingleMaxLimit()!=null&&prInvestorTableReq.getSingleMinLimit()!=null){
            if(prInvestorTableReq.getInvestorCreditLimit().compareTo(prInvestorTableReq.getInvestorLoanLimit())<0){
                throw new TxnBizException(TxnRespCode.BIZ_ERROR.getCode(), "授信额度要大于或等于放款额度");
            }
            if(prInvestorTableReq.getSingleMaxLimit().compareTo(prInvestorTableReq.getSingleMinLimit())<0){
                throw new TxnBizException(TxnRespCode.BIZ_ERROR.getCode(), "机构单笔贷款最大值要大于机构单笔贷款最小值");
            }
        }
        PrInvestorTable inv = BeanMapping.copy(prInvestorTableReq, PrInvestorTable.class);
        PrInvestorTable prInterestTable = extPrInvestorTableMapper.selectByTenIdAndInvestorId(inv.getTenantId(), inv.getInvestorId());
        if (prInterestTable != null) {
            logger.error(TxnRespCode.DATA_EXISTS.getMsg());
            throw new TxnException(TxnRespCode.DATA_EXISTS.getMsg());
        }
        /*查看此出资方额度下的产品id是否相同*/
        List<PrInvestorLimit> prInvestorLimit = prInvestorTableReq.getCon();
        Set<PrInvestorLimit> set = new TreeSet<>((o1, o2) -> {
            //==0表示重复
            int compareToResult = 1;
            if (o1.getProductId().equalsIgnoreCase(o2.getProductId())) {
                compareToResult = 0;
            }
            return compareToResult;
        });
        set.addAll(prInvestorLimit);
        if (new ArrayList<>(set).size() != prInvestorLimit.size()) {
            logger.error("产品id重复");
            throw new TxnException("产品id不能重复！");
        }
        //增加出资方参数
        try {
            inv.setId(segmentService.getId(Constant.PR_INVERTOR_TABLE));
        } catch (SegmentException e) {
            logger.error("主键生成错误",e);
            throw new TxnException(ErrorMsgConstant.ERROR_ID);
        }
        inv.setRecordVersionNumber(Constant.VERSION_NUMBER);
        extPrInvestorTableMapper.insertSelective(inv);

        //增加出资方额度
        List<PrInvestorLimit> list = prInvestorTableReq.getCon();
        /*if(prInvestorTableReq.getCon().size()==0){
            throw new TxnBizException(TxnRespCode.BIZ_ERROR.getCode(), "出资方额度至少配置一个");
        }*/
        for (PrInvestorLimit pr : list) {
            try {
                pr.setId(segmentService.getId(Constant.PR_INVESTOR_LIMIT));
            } catch (SegmentException e) {
                logger.error("主键生成错误", e);
                throw new TxnException(ErrorMsgConstant.ERROR_ID);
            }
            pr.setTenantId(prInvestorTableReq.getTenantId());
            pr.setUpdateBy(prInvestorTableReq.getUpdateBy());
            pr.setInvestorId(prInvestorTableReq.getInvestorId());
            pr.setOrganizationId(prInvestorTableReq.getOrganizationId());
            pr.setRecordVersionNumber(Constant.VERSION_NUMBER);
            extPrInvestorLimitMapper.insertSelective(pr);
        }

        return BeanMapping.copy(inv, PrInvestorTableRes.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(key = "'investorTable_'+#prInvestorTableReq.tenantId+'_'+#prInvestorTableReq.investorId")
    public PrInvestorTableRes modifyInvestorTable(PrInvestorTableReq prInvestorTableReq) throws TxnException {
        if(prInvestorTableReq.getInvestorCreditLimit()!=null&&prInvestorTableReq.getInvestorLoanLimit()!=null&&prInvestorTableReq.getSingleMaxLimit()!=null&&prInvestorTableReq.getSingleMinLimit()!=null){
            if(prInvestorTableReq.getInvestorCreditLimit().compareTo(prInvestorTableReq.getInvestorLoanLimit())<0){
                throw new TxnBizException(TxnRespCode.BIZ_ERROR.getCode(), "授信额度要大于或等于放款额度");
            }
            if(prInvestorTableReq.getSingleMaxLimit().compareTo(prInvestorTableReq.getSingleMinLimit())<0){
                throw new TxnBizException(TxnRespCode.BIZ_ERROR.getCode(), "机构单笔贷款最大值要大于机构单笔贷款最小值");
            }
        }
        /*查看此出资方额度下的产品id是否相同*/
        List<PrInvestorLimit> prInvestorLimits = prInvestorTableReq.getCon();
        Set<PrInvestorLimit> set = new TreeSet<>((o1, o2) -> {
            //==0表示重复
            int compareToResult = 1;
            if (o1.getProductId().equalsIgnoreCase(o2.getProductId())) {
                compareToResult = 0;
            }
            return compareToResult;
        });
        set.addAll(prInvestorLimits);
        if (new ArrayList<>(set).size() != prInvestorLimits.size()) {
            logger.error("产品id重复");
            throw new TxnException("产品id不能重复！");
        }
        PrInvestorTable investorTable = BeanMapping.copy(prInvestorTableReq, PrInvestorTable.class);
        // 更新出资方数据
        extPrInvestorTableMapper.updateByPrimaryKeySelectiveAndNotNull(investorTable);
        // 更新出资方额度表数据（先删后加）
        PrInvestorLimit prInvestorLimit = new PrInvestorLimit();
        prInvestorLimit.setTenantId(investorTable.getTenantId());
        prInvestorLimit.setInvestorId(investorTable.getInvestorId());
        List<PrInvestorLimit> list = extPrInvestorLimitMapper.selectByInvestorIdAndTenId(prInvestorLimit.getInvestorId(), prInvestorLimit.getTenantId());
        if (list != null && !list.isEmpty()) {
            for (PrInvestorLimit investorLimit:list){
                extPrInvestorLimitMapper.deleteByInvestorIdAndTenId(investorLimit.getInvestorId(),investorLimit.getTenantId());
            }

        }

        List<PrInvestorLimit> li = prInvestorTableReq.getCon();
//        if(prInvestorTableReq.getCon().size()==0){
//            throw new TxnBizException(TxnRespCode.BIZ_ERROR.getCode(), "出资方额度至少配置一个");
//        }
        for (PrInvestorLimit investorLimits : li) {
            try {
                investorLimits.setId(segmentService.getId(Constant.PR_INVESTOR_LIMIT));
            } catch (SegmentException e) {
                logger.error("主键生成错误", e);
                throw new TxnException(ErrorMsgConstant.ERROR_ID);
            }
            investorLimits.setTenantId(prInvestorTableReq.getTenantId());
            investorLimits.setUpdateBy(prInvestorTableReq.getUpdateBy());
            investorLimits.setInvestorId(prInvestorTableReq.getInvestorId());
            investorLimits.setOrganizationId(prInvestorTableReq.getOrganizationId());
            investorLimits.setRecordVersionNumber(Constant.VERSION_NUMBER);
            extPrInvestorLimitMapper.insertSelective(investorLimits);
        }

        return BeanMapping.copy(investorTable, PrInvestorTableRes.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(key = "'investorTable_'+#investorId+'_'+#tenantId")
    public Boolean removeByInvestorIdAndTenId(String investorId, String tenantId) throws TxnException {
        if (StringUtils.isBlank(investorId)||StringUtils.isBlank(tenantId)) {
            logger.error(TxnRespCode.NOT_EMPTY.getMsg());
            throw new TxnException(TxnRespCode.NOT_EMPTY.getMsg());
        }

        /*根据租户ID和出资方ID查询信息*/
        PrInvestorTable prInvestorTable = extPrInvestorTableMapper.selectByTenIdAndInvestorId(tenantId,investorId);

        /*获取查询信息的租户ID和出资方ID查询出资方额度表里的相关信息列表*/
        PrInvestorLimit prInvestorLimit = new PrInvestorLimit();
        prInvestorLimit.setTenantId(prInvestorTable.getTenantId());
        prInvestorLimit.setInvestorId(prInvestorTable.getInvestorId());
        List<PrInvestorLimit> list = extPrInvestorLimitMapper.selectByInvestorIdAndTenId(prInvestorLimit.getInvestorId(), prInvestorLimit.getTenantId());
        if (list!=null){
            for(PrInvestorLimit investorLimit:list){
                extPrInvestorLimitMapper.deleteByInvestorIdAndTenId(investorLimit.getInvestorId(), investorLimit.getTenantId());
            }
        }

        int a = extPrInvestorTableMapper.deleteByInvestorIdAndTenId(investorId,tenantId);
        return a > 0;
    }

    @Override
    public PrInvestorTableRes findByTenIdAndInvestorId(String tenantId, String investorId) throws TxnException {
        if (StringUtils.isBlank(tenantId)||StringUtils.isBlank(investorId)) {
            logger.error(TxnRespCode.NOT_EMPTY.getMsg());
            throw new TxnException(TxnRespCode.NOT_EMPTY.getMsg());
        }

        /*根据租户ID和出资方ID查询信息*/
        PrInvestorTable prInvestorTable = extPrInvestorTableMapper.selectByTenIdAndInvestorId(tenantId,investorId);

        /*获取查询信息的租户ID和出资方ID查询出资方额度表里的相关信息列表*/
        PrInvestorLimit prInvestorLimit = new PrInvestorLimit();
        prInvestorLimit.setTenantId(prInvestorTable.getTenantId());
        prInvestorLimit.setInvestorId(prInvestorTable.getInvestorId());
        List<PrInvestorLimit> list = extPrInvestorLimitMapper.selectByInvestorIdAndTenId(prInvestorLimit.getInvestorId(), prInvestorLimit.getTenantId());
        PrInvestorTableRes res = BeanMapping.copy(prInvestorTable, PrInvestorTableRes.class);
        res.setCon(list);
        return res;
    }

    @Cacheable(key = "'investorTable_'+#tenantId+'_'+#investorId")
    @Override
    public PrInvestorTable findInvestorByInvestorId(String investorId, String tenantId) throws TxnBizException {
        PrInvestorTable prInvestorTable = extPrInvestorTableMapper.selectByTenIdAndInvestorId(tenantId, investorId);
        if (prInvestorTable == null) {
            throw new TxnBizException(TxnRespCode.NO_DATA.getCode(), TxnRespCode.NO_DATA.getMsg());
        }
        return prInvestorTable;
    }

    @Override
    public List<PrInvestorTableRes> findAllByTenId(String tenantId) {
        List<PrInvestorTable> prInvestorTables = extPrInvestorTableMapper.selectByTenantId(tenantId,"1");
        return BeanMapping.copyList(prInvestorTables, PrInvestorTableRes.class);
    }

    /**
     * 根据资金方id租户id查询资金方额度信息
     *
     * @param investorId 资金方id
     * @param tenantId 租户id
     * @return PrInvestorLimit 资金方额度信息
     * @throws TxnBizException
     * @author liuyang
     * @date 2020-6-2
     */
    @Cacheable(key = "'investorLimit_'+#tenantId+'_'+#investorId")
    @Override
    public List<PrInvestorLimit> findInvestorLimitByInvestorId(String investorId, String tenantId) throws TxnBizException {
        List<PrInvestorLimit> list = extPrInvestorLimitMapper.selectByInvestorIdAndTenId(investorId, tenantId);
        if (list == null) {
            throw new TxnBizException(TxnRespCode.NO_DATA.getCode(), TxnRespCode.NO_DATA.getMsg(ErrorMsgConstant.NO_INTEREST_DATA));
        }
        return list;
    }



    /**
     * 出资方额度使用
     *
     * @param investorLimitReq 出资方额度使用请求实体
     * @return HandleInvestorLimitRes 资金方额度信息
     * @throws TxnBizException
     * @author liuyang
     * @date 2020-6-8
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public HandleInvestorLimitRes handleInvestorLimit(HandleInvestorLimitReq investorLimitReq) throws TxnBizException {

        // 初始化返回对象
        HandleInvestorLimitRes res = new HandleInvestorLimitRes();
        res.setInvestorId(investorLimitReq.getInvestorId());

        // 取得金额，额度类型，使用类型
        BigDecimal amount = investorLimitReq.getAmount();
        String creditType = investorLimitReq.getCreditType();
        String useType = investorLimitReq.getUseType();

        // 取得出资方额度信息
        PrInvestorLimit investorLimit = extPrInvestorLimitMapper.selectByInvestorIdAndProductId(investorLimitReq.getInvestorId(), investorLimitReq.getProductId(), investorLimitReq.getTenantId());
        if (investorLimit == null) {
            throw new TxnBizException(TxnRespCode.NO_DATA.getCode(), TxnRespCode.NO_DATA.getMsg(ErrorMsgConstant.NO_INTEREST_DATA));
        }

        // 取得出资方信息
        PrInvestorTable interestTable = extPrInvestorTableMapper.selectByTenIdAndInvestorId(investorLimitReq.getTenantId(), investorLimitReq.getInvestorId());

        // 设置更新对象
        PrInvestorLimit updateInvestorLimit=new PrInvestorLimit();
        updateInvestorLimit.setId(investorLimit.getId());
        updateInvestorLimit.setTenantId(investorLimit.getTenantId());
        updateInvestorLimit.setOrganizationId(investorLimit.getOrganizationId());

        // 设置更新对象
        PrInvestorTable updateInterestTable=new PrInvestorTable();
        updateInterestTable.setId(interestTable.getId());
        updateInterestTable.setTenantId(interestTable.getTenantId());
        updateInterestTable.setOrganizationId(interestTable.getOrganizationId());

        // 授信
        if (Constant.INVESTOR_LIMIT_CREDITTYPE_C.equals(creditType)) {
            // 使用
            if (Constant.INVESTOR_LIMIT_USETYPE_U.equals(useType)) {
                if (amount.compareTo(investorLimit.getAvailCreditLimit()) > 0 || amount.compareTo(interestTable.getInvestorAvailCreditLimit()) > 0) {
                    res.setUseResult(Constant.INVESTOR_LIMIT_USE_F);
                    res.setFailReason(ErrorMsgConstant.NOT_INVESTOR_LIMIT);
                    return res;
                } else {
                    updateInvestorLimit.setAvailCreditLimit(investorLimit.getAvailCreditLimit().subtract(amount));
                    updateInvestorLimit.setUsedCreditLimit(investorLimit.getUsedCreditLimit().add(amount));
                    updateInterestTable.setInvestorAvailCreditLimit(interestTable.getInvestorAvailCreditLimit().subtract(amount));
                    updateInterestTable.setInvestorUsedCreditLimit(interestTable.getInvestorUsedCreditLimit().add(amount));
                }
            }
            // 恢复
            else if (Constant.INVESTOR_LIMIT_USETYPE_R.equals(useType)) {
                updateInvestorLimit.setAvailCreditLimit(investorLimit.getAvailCreditLimit().add(amount));
                updateInvestorLimit.setUsedCreditLimit(investorLimit.getUsedCreditLimit().subtract(amount));
                updateInterestTable.setInvestorAvailCreditLimit(interestTable.getInvestorAvailCreditLimit().add(amount));
                updateInterestTable.setInvestorUsedCreditLimit(interestTable.getInvestorUsedCreditLimit().subtract(amount));
            }
        }
        // 贷款
        else if (Constant.INVESTOR_LIMIT_CREDITTYPE_L.equals(creditType)) {
            // 使用
            if (Constant.INVESTOR_LIMIT_USETYPE_U.equals(useType)) {
                if (amount.compareTo(investorLimit.getDailyAvailLimit()) > 0 || amount.compareTo(investorLimit.getAvailLimit()) > 0
                || amount.compareTo(interestTable.getInvestorAvailLoanLimit()) > 0) {
                    res.setUseResult(Constant.INVESTOR_LIMIT_USE_F);
                    res.setFailReason(ErrorMsgConstant.NOT_INVESTOR_LIMIT);
                    return res;
                } else {
                    updateInvestorLimit.setDailyAvailLimit(investorLimit.getDailyAvailLimit().subtract(amount));
                    updateInvestorLimit.setAvailLimit(investorLimit.getAvailLimit().subtract(amount));
                    updateInvestorLimit.setDailyUsedLimit(investorLimit.getDailyUsedLimit().add(amount));
                    updateInvestorLimit.setUsedLimit(investorLimit.getUsedLimit().add(amount));
                    updateInterestTable.setInvestorAvailLoanLimit(interestTable.getInvestorAvailLoanLimit().subtract(amount));
                    updateInterestTable.setInvestorUsedLoanLimit(interestTable.getInvestorUsedLoanLimit().add(amount));
                }
            }
            // 恢复
            else if (Constant.INVESTOR_LIMIT_USETYPE_R.equals(useType)) {
                BigDecimal dailyAvailLimit = investorLimit.getDailyAvailLimit().add(amount);
                dailyAvailLimit = dailyAvailLimit.compareTo(investorLimit.getDailyMaxLimit())>0 ? investorLimit.getDailyMaxLimit() : dailyAvailLimit;
                BigDecimal dailyUsedLimit = investorLimit.getDailyUsedLimit().subtract(amount);
                dailyUsedLimit = dailyUsedLimit.compareTo(BigDecimal.ZERO)<0 ? BigDecimal.ZERO : dailyUsedLimit;
                updateInvestorLimit.setDailyAvailLimit(dailyAvailLimit);
                updateInvestorLimit.setAvailLimit(investorLimit.getAvailLimit().add(amount));
                updateInvestorLimit.setDailyUsedLimit(dailyUsedLimit);
                updateInvestorLimit.setUsedLimit(investorLimit.getUsedLimit().subtract(amount));
                updateInterestTable.setInvestorAvailLoanLimit(interestTable.getInvestorAvailLoanLimit().add(amount));
                updateInterestTable.setInvestorUsedLoanLimit(interestTable.getInvestorUsedLoanLimit().subtract(amount));
            }
        }

        // 更新出资方额度
        extPrInvestorLimitMapper.extUpdateByPrimaryKeySelective(updateInvestorLimit);

        // 更新出资方信息
        extPrInvestorTableMapper.extUpdateByPrimaryKeySelective(updateInterestTable);

        // 设置返回结果
        res.setUseResult(Constant.INVESTOR_LIMIT_USE_S);
        return res;

    }
}
